{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "import numpy as np\n",
    "cimport numpy as np\n",
    "\n",
    "w, h = 400, 400  # Size of the screen in pixels.\n",
    "\n",
    "def normalize(x):\n",
    "    # This function normalizes a vector.\n",
    "    x /= np.linalg.norm(x)\n",
    "    return x\n",
    "\n",
    "def intersect_sphere(O, D, S, R):\n",
    "    # Return the distance from O to the intersection\n",
    "    # of the ray (O, D) with the sphere (S, R), or\n",
    "    # +inf if there is no intersection.\n",
    "    # O and S are 3D points, D (direction) is a\n",
    "    # normalized vector, R is a scalar.\n",
    "    a = np.dot(D, D)\n",
    "    OS = O - S\n",
    "    b = 2 * np.dot(D, OS)\n",
    "    c = np.dot(OS, OS) - R*R\n",
    "    disc = b*b - 4*a*c\n",
    "    if disc > 0:\n",
    "        distSqrt = np.sqrt(disc)\n",
    "        q = (-b - distSqrt) / 2.0 if b < 0 \\\n",
    "            else (-b + distSqrt) / 2.0\n",
    "        t0 = q / a\n",
    "        t1 = c / q\n",
    "        t0, t1 = min(t0, t1), max(t0, t1)\n",
    "        if t1 >= 0:\n",
    "            return t1 if t0 < 0 else t0\n",
    "    return np.inf\n",
    "\n",
    "def trace_ray(O, D):\n",
    "    # Find first point of intersection with the scene.\n",
    "    t = intersect_sphere(O, D, position, radius)\n",
    "    # No intersection?\n",
    "    if t == np.inf:\n",
    "        return\n",
    "    # Find the point of intersection on the object.\n",
    "    M = O + D * t\n",
    "    N = normalize(M - position)\n",
    "    toL = normalize(L - M)\n",
    "    toO = normalize(O - M)\n",
    "    # Ambient light.\n",
    "    col = ambient\n",
    "    # Lambert shading (diffuse).\n",
    "    col += diffuse * max(np.dot(N, toL), 0) * color\n",
    "    # Blinn-Phong shading (specular).\n",
    "    col += specular_c * color_light * \\\n",
    "        max(np.dot(N, normalize(toL + toO)), 0) \\\n",
    "           ** specular_k\n",
    "    return col\n",
    "\n",
    "def run():\n",
    "    img = np.zeros((h, w, 3))\n",
    "    # Loop through all pixels.\n",
    "    for i, x in enumerate(np.linspace(-1., 1., w)):\n",
    "        for j, y in enumerate(np.linspace(-1., 1., h)):\n",
    "            # Position of the pixel.\n",
    "            Q[0], Q[1] = x, y\n",
    "            # Direction of the ray going through the optical center.\n",
    "            D = normalize(Q - O)\n",
    "            depth = 0\n",
    "            # Launch the ray and get the color of the pixel.\n",
    "            col = trace_ray(O, D)\n",
    "            if col is None:\n",
    "                continue\n",
    "            img[h - j - 1, i, :] = np.clip(col, 0, 1)\n",
    "    return img\n",
    "\n",
    "# Sphere properties.\n",
    "position = np.array([0., 0., 1.])\n",
    "radius = 1.\n",
    "color = np.array([0., 0., 1.])\n",
    "diffuse = 1.\n",
    "specular_c = 1.\n",
    "specular_k = 50\n",
    "\n",
    "# Light position and color.\n",
    "L = np.array([5., 5., -10.])\n",
    "color_light = np.ones(3)\n",
    "ambient = .05\n",
    "\n",
    "# Camera.\n",
    "O = np.array([0., 0., -1.])  # Position.\n",
    "Q = np.array([0., 0., 0.])  # Pointing to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "podoc": {
     "output_text": "<matplotlib.figure.Figure at 0xa468c18>"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0xa468c18>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "img = run()\n",
    "fig, ax = plt.subplots(1, 1, figsize=(10, 10))\n",
    "ax.imshow(img)\n",
    "ax.set_axis_off()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.57 s ± 19.1 ms per loop (mean ± std. dev. of 7 runs,\n",
      "    1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit run()"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
